/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司 All rights reserved.
 */
package cn.net.ecode.modules.sys.web;

import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import cn.net.ecode.common.config.Global;
import cn.net.ecode.common.mapper.JsonMapper;
import cn.net.ecode.common.security.shiro.session.SessionDAO;
import cn.net.ecode.common.utils.CacheUtils;
import cn.net.ecode.common.utils.CookieUtils;
import cn.net.ecode.common.utils.Encodes;
import cn.net.ecode.common.utils.StringUtils;
import cn.net.ecode.common.web.BaseController;
import cn.net.ecode.common.web.Servlets;
import cn.net.ecode.modules.sys.entity.Menu;
import cn.net.ecode.modules.sys.entity.User;
import cn.net.ecode.modules.sys.security.AuthorizingRealm.Principal;
import cn.net.ecode.modules.sys.security.FormAuthenticationFilter;
import cn.net.ecode.modules.sys.security.UsernamePasswordToken;
import cn.net.ecode.modules.sys.service.UserService;
import cn.net.ecode.modules.sys.utils.UserUtils;

/**
 * 登录Controller
 * @author ThinkGem
 * @version 2015-2-3
 */
@Controller
public class LoginController extends BaseController{

	@Autowired
	private SessionDAO sessionDAO;
	
	@Autowired
	private UserService userService;
	
	/**
	 * 管理登录
	 */
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET)
	public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
		// 地址中如果包含JSESSIONID，则跳转一次，去掉JSESSIONID信息。
		if (request.getRequestURI().contains(";JSESSIONID=")){
			String queryString = request.getQueryString();
			queryString = queryString == null ? "" : "?" + queryString;
			return "redirect:" + adminPath + "/login" + queryString;
		}
		
		// 如果是登录操作，跳转到此，则认为是登录失败（支持GET登录时传递__login=true参数）
		if (WebUtils.isTrue(request, "__login")){
			return loginFail(request, response, model);
		}

		// 打印当前活动Session个数
		if (logger.isDebugEnabled()){
			logger.debug("login, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}
		
		// 如果已登录，再次访问主页，则退出原账号。
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
			CookieUtils.setCookie(response, "LOGINED", "false");
		}

		Principal principal = UserUtils.getPrincipal();
		
		// 如果已经登录，则跳转到管理首页
		if(principal != null){
			String queryString = request.getQueryString();
			queryString = queryString == null ? "" : "?" + queryString;
			return "redirect:" + adminPath + queryString;
		}
		
		// 是否显示验证码
		model.addAttribute("isValidateCodeLogin", Integer.valueOf(Global.getConfig("loginFailedToValidateCode")) == 0);
		
		// 如果是Ajax请求，返回Json字符串。
		if (Servlets.isAjaxRequest((HttpServletRequest)request)){
			model.addAttribute("result", Global.FALSE);
			model.addAttribute("message", "未登录或登录超时。请重新登录，谢谢！");
			Servlets.renderStringToJsonP(response, model);
			return null;
		}
		
		// 返回指定用户类型的登录页视图
		String params = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_PARAMS_PARAM);
		String userType = new Principal(new User(), params).getParam("userType");
		if (StringUtils.isNotBlank(userType)){
			String view = UserUtils.getUserTypeValue(userType, "loginView");
			if(StringUtils.isNotBlank(view)){
				return view;
			}
		}
		
//		String view;
//		view = "/WEB-INF/views/modules/sys/sysLogin.jsp";
//		view = "classpath:";
//		view += "jar:file:/D:/GitHub/ecode_jeesite/src/main/webapp/WEB-INF/lib/jeesite.jar!";
//		view += "/"+getClass().getName().replaceAll("\\.", "/").replace(getClass().getSimpleName(), "")+"view/sysLogin";
//		view += ".jsp";
		return Global.getConfig("web.view.sysLogin");
	}

	/**
	 * 登录失败，真正登录的POST请求由Filter完成
	 */
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)
	public String loginFail(HttpServletRequest request, HttpServletResponse response, Model model) {
		Principal principal = UserUtils.getPrincipal();
		
		// 如果已经登录，则跳转到管理首页
		if(principal != null){
			if (Servlets.isAjaxRequest(request)){
				Session session = UserUtils.getSession();
				model.addAttribute("result", Global.TRUE);
				model.addAttribute("message", "已经登录，请进入首页！");
				model.addAttribute("sessionid", (String)session.getId());
				Servlets.renderStringToJsonP(response, model);
				return null;
			}
			String queryString = request.getQueryString();
			queryString = queryString == null ? "" : "?" + queryString;
			return "redirect:" + adminPath + queryString;
		}
		
		String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
		boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
		boolean rememberUserCode = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM);
		String params = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_PARAMS_PARAM);
		String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
		String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);

		model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM, rememberUserCode);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAMS_PARAM, params);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, message);

		if (logger.isDebugEnabled()){
			logger.debug("login fail, active session size: {}, message: {}, exception: {}", 
					sessionDAO.getActiveSessions(false).size(), message, exception);
		}
		
		// 非授权异常，登录失败，验证码加1。
		if (!UnauthorizedException.class.getName().equals(exception)){
			// 如果使用了集团用户模式，则获取集团Code
			String corpCode = null;
			if (Global.isUseCorpModel()){
				if (StringUtils.isNotBlank(params)){
					Map<String, Object> map = JsonMapper.fromJsonString(params, Map.class);
					if (map != null){
						corpCode = (String)map.get("corpCode");
					}
				}
				if (StringUtils.isBlank(corpCode)){
					throw new AuthenticationException("msg:请选择您要登录的集团公司.");
				}
			}
			model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, corpCode, true, false));
		}

		// 登录操作如果是Ajax操作，直接返回登录信息字符串。
		if (Servlets.isAjaxRequest(request)){
			model.addAttribute("result", Global.FALSE);
			Servlets.renderString(response, model);
			return null;
		}
		
		// 返回指定用户类型的登录页视图
		String userType = new Principal(new User(), params).getParam("userType");
		if (StringUtils.isNotBlank(userType)){
			String view = UserUtils.getUserTypeValue(userType, "loginView");
			if(StringUtils.isNotBlank(view)){
				return view;
			}
		}
		
		return Global.getConfig("web.view.sysLogin");
	}

	/**
	 * 单点登录（如已经登录，则直接跳转）
	 * @param username 登录用户名（loginCode）
	 * @param token 登录令牌，令牌组成：sso密钥+用户名+日期，进行md5加密，举例： 
	 * 		String secretKey = Global.getConfig("shiro.sso.secretKey");
	 * 		String token = Digests.md5(secretKey + username + DateUtils.getDate("yyyyMMdd"));
	 * @param url 登录成功后跳转的url地址。
	 * @param relogin 是否重新登录，需要重新登录传递true
	 * 例如：http://localhost/project/sso/{username}/{token}?url=xxx&relogin=true
	 */
	@RequestMapping(value = "sso/{username}/{token}")
	public String sso(@PathVariable String username, @PathVariable String token, 
			@RequestParam(required=true) String url, String relogin, Model model) {
		Principal principal = UserUtils.getPrincipal();
		// 如果已经登录，并且不重新登录，则直接跳转到目标页
		if(principal != null && !BooleanUtils.toBoolean(relogin)){
			return "redirect:" + Encodes.urlDecode2(url);
		}
		// 进行单点登录
		if (token != null){
			UsernamePasswordToken upt = new UsernamePasswordToken();
			try {
				upt.setUsername(username); // 登录用户名
				upt.setPassword(token.toCharArray()); // 密码组成：sso密钥+用户名+日期，进行md5加密，举例： Digests.md5(secretKey+username+20150101)）
				upt.setParams(upt.toString()); // 单点登录识别参数，see： AuthorizingRealm.assertCredentialsMatch
			} catch (Exception ex){
	        	if (!ex.getMessage().startsWith("msg:")){
	        		ex = new AuthenticationException("msg:授权令牌错误，请联系管理员。");
	        	}
	        	model.addAttribute("exception", ex);
			}
			try {
				UserUtils.getSubject().login(upt);
				return "redirect:" + Encodes.urlDecode2(url);
	        } catch (AuthenticationException ae) {
	        	if (!ae.getMessage().startsWith("msg:")){
	        		ae = new AuthenticationException("msg:授权错误，请检查用户配置，若不能解决，请联系管理员。");
	        	}
	        	model.addAttribute("exception", ae);
	        }
		}
		return "error/403";
	}
	
	/**
	 * 登录成功，进入管理首页
	 */
	@RequiresPermissions("user")
	@RequestMapping(value = {"${adminPath}", "${adminPath}/index"})
	public String index(HttpServletRequest request, HttpServletResponse response, Model model) {
		// 地址中如果包含JSESSIONID，则跳转一次，去掉JSESSIONID信息。
		if (request.getRequestURI().contains(";JSESSIONID=")){
			String queryString = request.getQueryString();
			queryString = queryString == null ? "" : "?" + queryString;
			return "redirect:" + adminPath + queryString;
		}
		
		//获取登录用户信息
		Principal principal = UserUtils.getPrincipal();

		// 登录成功后，验证码计算器清零
		isValidateCodeLogin(principal.getId(), principal.getParam("corpCode"), false, true);
		
		// 打印当前活动Session个数
		if (logger.isDebugEnabled()){
			logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}

		//获取当前会话对象
		Session session = UserUtils.getSession();
		
		// 设置共享SessionId的Cookie值，睿思BI使用。
		String cookieName = Global.getProperty("session.shareSessionIdCookieName");
		CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
		
		// 登录操作如果是Ajax操作，直接返回登录信息字符串。
		if (Servlets.isAjaxRequest(request)){
			model.addAttribute("result", Global.TRUE);
			model.addAttribute("message", "获取信息成功！");
			model.addAttribute("sessionid", (String)session.getId());
			model.addAttribute("user", UserUtils.getUser()); // 当前用户信息
			// 获取当前用户权限字符串
			if (WebUtils.isTrue(request, "permi")){
				Set<String> set = Sets.newLinkedHashSet();
				for (Menu menu : UserUtils.getMenuList()){
					if (StringUtils.isNotBlank(menu.getPermission())){
						for (String s : StringUtils.split(menu.getPermission(), ",")){
							set.add(s);
						}
					}
				}
				model.addAttribute("permi", set);
			}
			// 仅获取睿思BI的权限字符串
			if (WebUtils.isTrue(request, "rsbi")){
				Set<String> set = Sets.newLinkedHashSet();
				for (Menu menu : UserUtils.getMenuList()){
					if (StringUtils.isNotBlank(menu.getPermission())){
						for (String s : StringUtils.split(menu.getPermission(), ",")){
							if (StringUtils.startsWith(s, "rsbi:")){
								set.add(s);
							}
						}
					}
				}
				model.addAttribute("rsbi", set);
			}
			Servlets.renderStringToJsonP(response, model);
			return null;
		}
		
		// 如果已登录，再次访问主页，则退出原账号。
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
			String logined = CookieUtils.getCookie(request, "LOGINED");
			if (StringUtils.isBlank(logined) || "false".equals(logined)){
				CookieUtils.setCookie(response, "LOGINED", "true");
			}else if (StringUtils.equals(logined, "true")){
				UserUtils.getSubject().logout();
				CookieUtils.setCookie(response, "LOGINED", "false");
				String queryString = request.getQueryString();
				queryString = queryString == null ? "" : "?" + queryString;
				return "redirect:" + adminPath + "/login" + queryString;
			}
		}
		
//		// 登录成功后，获取上次登录的当前站点ID
//		UserUtils.putCache("siteId", StringUtils.toLong(CookieUtils.getCookie(request, "siteId")));
		
		// 返回指定用户类型的首页视图
		String userType = principal.getParam("userType");
		if (StringUtils.isNotBlank(userType)){
			String view = UserUtils.getUserTypeValue(userType, "indexView");
			if(StringUtils.isNotBlank(view)){
				return view;
			}
		}
		
		// 验证当前用户密码，是否是初始密码，如果是，则在前台页面进行提醒。
		if (BooleanUtils.toBoolean(Global.getConfig("user.initPasswordMobifyRemind"))){
			model.addAttribute("isInitPassword", UserService.validatePassword(
					Global.getConfig("user.initPassword"), UserUtils.getUser().getPassword()));
		}
		
		// 返回主页面视图
		return Global.getConfig("web.view.sysIndex");
	}

	/**
	 * 步骤的首页（大表单，上一步，下一步）
	 */
	@RequiresPermissions("user")
	@RequestMapping(value = "${adminPath}/stepIndex")
	public String stepIndex(HttpServletRequest request, HttpServletResponse response, Model model) {
		return "modules/sys/sysStepIndex";
	}
	
	/**
	 * 个人桌面页面
	 */
	@RequiresPermissions("user")
	@RequestMapping(value = "desktop")
	public String desktop(HttpServletRequest request, HttpServletResponse response, Model model) {
		return "modules/sys/sysDesktop";
	}
	
	/**
	 * 获取在线用户数
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "onlineCount")
	@ResponseBody
	public Integer onlineCount(HttpServletRequest request, HttpServletResponse response) {
		return sessionDAO.getActiveSessions(false).size();
	}
	
	/**
	 * 获取主题方案
	 */
	@RequestMapping(value = "theme/{theme}")
	public String getThemeInCookie(@PathVariable String theme, HttpServletRequest request, HttpServletResponse response){
		if (StringUtils.isNotBlank(theme)){
			CookieUtils.setCookie(response, "theme", theme);
		}else{
			theme = CookieUtils.getCookie(request, "theme");
		}
		return "redirect:"+request.getParameter("url");
	}
	
	/**
	 * 是否是验证码登录
	 * @param useruame 用户名
	 * @param isFail 计数加1
	 * @param clean 计数清零
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static boolean isValidateCodeLogin(String useruame, String corpCode, boolean isFail, boolean clean){
		Map<String, Integer> loginFailedMap = (Map<String, Integer>)CacheUtils.get("loginFailedMap");
		if (loginFailedMap==null){
			loginFailedMap = Maps.newHashMap();
			CacheUtils.put("loginFailedMap", loginFailedMap);
		}
		String key = useruame;
		if (corpCode != null){
			key = corpCode + "_" + useruame;
		}
		Integer loginFailedNum = loginFailedMap.get(key);
		if (loginFailedNum==null){
			loginFailedNum = 0;
		}
		if (isFail){
			loginFailedNum++;
			loginFailedMap.put(key, loginFailedNum);
		}
		if (clean){
			loginFailedMap.remove(key);
		}
		return loginFailedNum >= Integer.valueOf(Global.getConfig("loginFailedToValidateCode"));
	}
	
//	@ResponseBody
//	@RequestMapping(value = "forgetPassword")
//	public String forgetPassword(User user,HttpServletRequest request) {
//		String loginName = user.getUserCode();
//		if (StringUtils.isBlank(loginName)) {
//			loginName = request.getParameter("loginName");
//		}
//
//		user = userService.get(loginName);
//		
//		String data = JsonMapper.toJsonString(user);
//		logger.debug("[forgetPassword] data:" + data);
//		return data;
//	}
//	
//	@ResponseBody
//	@RequestMapping(value = "resetPassword")
//	public String resetPassword(User user,HttpServletRequest request) {
//		User u = userService.get(user.getId());
//
//		String type = request.getParameter("type");
//		String validatCode = ""; // 验证码信息
//		if("1".equals(type)){
//			// 邮箱
//			if(StringUtils.equals(u.getEmail(), user.getEmail())){
//				validatCode = StringUtils.getRandomStr(12);
//				// TODO 发送校验码
//				String subject = "易科德提醒：验证码";
//				String message = "尊敬的"+user.getEmail()+",您好!\n";
//				message += "我们收到了您重置密码的申请，请在验证码栏输入"+validatCode+"完成验证。\n";
//				message += "本邮件由系统自动发出，请勿回复。\n\n\n";
//				message += "感谢您的使用。\n";
//				message += "青岛易科德软件有限公司";
//
//				SendMailUtil.sendEmail(user.getEmail(), subject, message);
//				
//				u.setExtendS1(validatCode);
//				userService.updateUserInfo(u);
//				return renderResult(Global.TRUE,"邮件已发送，请输入验证码！");
//			}
//			return renderResult(Global.FALSE,"邮箱地址不正确！");
//		}else if("2".equals(type)){
//			// 密保问题
//			if (StringUtils.equals(u.getPwdQuestionAnswer(),
//					user.getPwdQuestionAnswer())
//					&& StringUtils.equals(u.getPwdQuestionAnswer2(),
//							user.getPwdQuestionAnswer2())
//					&& StringUtils.equals(u.getPwdQuestionAnswer3(),
//							user.getPwdQuestionAnswer3())) {
//				return renderResult(Global.TRUE,"密保问题校验成功！");
//			}
//			return renderResult(Global.FALSE,"密保问题答案错误！");
//		}else if("3".equals(type)){
//			// 手机
//			if(StringUtils.equals(u.getMobile(), user.getMobile())){
//				// TODO 发送短信，获取验证码
//				validatCode = StringUtils.getRandomStr(4);
//				u.setExtendS1(validatCode);
//				userService.updateUserInfo(u);
//				return renderResult(Global.TRUE,"手机短信已发送，请输入验证码！");
//			}
//			return renderResult(Global.FALSE,"手机号码不正确！");
//		}
//		
//		return null;
//	}
//	
//	@ResponseBody
//	@RequestMapping(value = "checkValidat")
//	public String checkValidat(User user,HttpServletRequest request) {
//		User u = userService.get(user.getId());
//		if(StringUtils.equals(user.getExtendS1(), u.getExtendS1())){
//			return renderResult(Global.TRUE,"校验成功！");
//		}
//		return renderResult(Global.FALSE,"验证码错误");
//	}
//	
//	@ResponseBody
//	@RequestMapping(value = "setNewPassword")
//	public String setNewPassword(User user,HttpServletRequest request) {
//		User u = userService.get(user.getId());
//		u.setPassword(user.getPassword());
//		userService.updatePassword(u.getUserCode(),u.getPassword());
//		return renderResult(Global.TRUE,"密码修改成功");
//	}
	
}
